
/*  *  *  *  *  *  *  *  *  *  *
 *     对cesium分析的扩展      *
 *  *  *  *  *  *  *  *  *  *  */
;(function() {
	function _() {
		this.PI = 3.141592653589793238;
		this.a = 6378137.0;
		this.b = 6356752.3142
		this.f = (this.a - this.b) / this.a;
		this.e_sq = this.f * (2.0 - this.f);
		this.ee = 0.00669437999013;
		this.WGSF = 1 / 298.257223563;
		this.WGSe2 = this.WGSF * (2 - this.WGSF);
		this.WGSa = 6378137.00000;
		this.EPSILON = 1.0e-12;
	}
	_.prototype.CalculateCoordinates = function (point, azimuth, elevation, distance) {
			var vertical_height = distance * Math.sin(2 * this.PI / 360 * elevation);//垂直高度
			var  horizontal_distance = distance * Math.cos(2 * this.PI / 360 * elevation);//水平距离
			if (azimuth > 360) azimuth = azimuth % 360;
			if (azimuth < 0) azimuth = 360 + (azimuth % 360);

			var point = this.lonLat2WebMercator(point);
			var lnglat = null;

			if (azimuth <= 90) {//第四象限
				var x_length = horizontal_distance * Math.cos(2 * this.PI / 360 * azimuth);
				var y_length = horizontal_distance * Math.sin(2 * this.PI / 360 * azimuth);
					lnglat = {
							x: point.x + x_length,
							y: point.y - y_length
					}
			} else if (azimuth > 90 && azimuth <= 180) {//第三象限
				var x_length = horizontal_distance * Math.sin(2 * this.PI / 360 * (azimuth - 90));
				var y_length = horizontal_distance * Math.cos(2 * this.PI / 360 * (azimuth - 90));
					lnglat = {
							x: point.x - x_length,
							y: point.y - y_length
					}
			} else if (azimuth > 180 && azimuth <= 270) {//第二象限
				var x_length = horizontal_distance * Math.cos(2 * this.PI / 360 * (azimuth - 180));
				var y_length = horizontal_distance * Math.sin(2 * this.PI / 360 * (azimuth - 180));
					lnglat = {
							x: point.x - x_length,
							y: point.y + y_length
					}
			} else {//第一象限
				var x_length = horizontal_distance * Math.sin(2 * this.PI / 360 * (azimuth - 270));
				var y_length = horizontal_distance * Math.cos(2 * this.PI / 360 * (azimuth - 270));
					lnglat = {
							x: point.x + x_length,
							y: point.y + y_length
					}
			}
			lnglat = this.webMercator2LonLat(lnglat);
			return {
					lng: lnglat.x,
					lat: lnglat.y,
					height: vertical_height
			}
	}
	/*
			*经纬度转Web墨卡托
			*@lonLat 经纬度
			*/
	_.prototype.lonLat2WebMercator = function (lonLat) {
			let x = lonLat.x * this.a / 180;
			let y = Math.log(Math.tan((90 + lonLat.y) * this.PI / 360)) / (this.PI / 180);
			y = y * this.a / 180;
			return {
					x: x,
					y: y
			}
	}
	
	/*
			*Web墨卡托转经纬度
			*@mercator 平面坐标
			*/
	_.prototype.webMercator2LonLat = function (mercator) {
			let x = mercator.x / this.a * 180;
			let y = mercator.y / this.a * 180;
			y = 180 / this.PI * (2 * (Math.exp(y * this.PI / 180)) - this.PI / 2);
			return {
					x: x,
					y: y
			}
	}

	_.prototype.get_atan = function (z, y) {
			let x;
			if (z == 0) {
					x = this.PI / 2;
			} else {
					if (y == 0) {
							x = this.PI;
					} else {
							x = Math.atan(Math.abs(y / z));
							if ((y > 0) && (z < 0)) {
									x = this.PI - x;
							} else if ((y < 0) && (z < 0)) {
									x = this.PI + x;
							} else if ((y < 0) && (z > 0)) {
									x = 2 * this.M_PI - x;
							}
					}
			}
			return x;
	}
	//WGS84转ECEF坐标系
	_.prototype.ConvertLLAToXYZ = function (LLACoor) {
			let lon = this.PI / 180 * LLACoor.longitude;
			let lat = this.PI / 180 * LLACoor.latitude;
			let H = LLACoor.altitude;
			let N0 = this.a / Math.sqrt(1.0 - this.ee * Math.sin(lat) * Math.sin(lat));
			let x = (N0 + H) * Math.cos(lat) * Math.cos(lon);
			let y = (N0 + H) * Math.cos(lat) * Math.sin(lon);
			let z = (N0 * (1.0 - this.ee) + H) * Math.sin(lat);
			return {
					x: x,
					y: y,
					z: z
			}
	}

	//ECEF坐标系转WGS84
	_.prototype.ConvertXYZToLLA = function (XYZCoor) {
			let longitude = this.get_atan(XYZCoor.x, XYZCoor.y);
			if (longitude < 0) {
					longitude = longitude + this.PI;
			}
			let latitude = this.get_atan(Math.sqrt(XYZCoor.x * XYZCoor.x + XYZCoor.y * XYZCoor.y), XYZCoor.z);

			let W = Math.sqrt(1 - this.WGSe2 * Math.sin(latitude) * Math.sin(latitude));
			let N = this.WGSa / W;
			let B1;
			do {
					B1 = latitude;
					W = Math.sqrt(1 - this.WGSe2 * Math.sin(B1) * Math.sin(B1));
					N = this.WGSa / W;
					latitude = this.get_atan(Math.sqrt(XYZCoor.x * XYZCoor.x + XYZCoor.y * XYZCoor.y), (XYZCoor.z + N * this.WGSe2 * Math.sin(B1)));
			}
			while (Math.abs(latitude - B1) > this.EPSILON);

			altitude = Math.sqrt(XYZCoor.x * XYZCoor.x + XYZCoor.y * XYZCoor.y) / Math.cos(latitude) - this.WGSa / Math.sqrt(1 - this.WGSe2 * Math.sin(latitude) * Math.sin(latitude));

			return {
					longitude: longitude * 180 / this.PI,
					latitude: latitude * 180 / this.PI,
					altitude: altitude
			}
	}
	/*北东天坐标系转WGS84
	@ a A点坐标
	@ p 相对参数，距离、方位角、仰角
	*/
		//	俯视角pitch -elevation 
	//航向角heading（yaw） -azimuth 
	_.prototype.enu_to_ecef = function (a, p) {
			//距离
			let distance = p.distance;
			//方位角
			let azimuth = p.azimuth;
			//仰角
			let elevation = p.elevation;

			let zUp = elevation >= 0 ? distance * Math.sin(this.PI / 180 * elevation) : (-1) * distance * Math.sin(this.PI / 180 * Math, abs(elevation));

			let d = distance * Math.cos(this.PI / 180 * Math.abs(elevation));
			let xEast;
			let yNorth;
			if (azimuth <= 90) {
					xEast = d * Math.sin(this.PI / 180 * azimuth);
					yNorth = d * Math.cos(this.PI / 180 * azimuth);
			} else if (azimuth > 90 && azimuth < 180) {
					xEast = d * Math.cos(this.PI / 180 * (azimuth - 90));
					yNorth = (-1)*d * Math.sin(this.PI / 180 * (azimuth - 90));
			} else if (azimuth > 180 && azimuth < 270) {
					xEast = (-1) * d * Math.sin(this.PI / 180 * (azimuth - 180));
					yNorth =(-1) *  d * Math.cos(this.PI / 180 * (azimuth - 180));
			} else {
					xEast = (-1) * d * Math.sin(this.PI / 180 * (360 - azimuth));
					yNorth =  d * Math.cos(this.PI / 180 * (360 - azimuth));
			}

			let lamb = this.radians(a.latitude);
			let phi = this.radians(a.longitude);
			let h0 = a.altitude;

			let s = Math.sin(lamb);
			let N = this.a / Math.sqrt(1.0 - this.e_sq * s * s);

			let sin_lambda = Math.sin(lamb);
			let cos_lambda = Math.cos(lamb);

			let sin_phi = Math.sin(phi);
			let cos_phi = Math.cos(phi);

			let x0 = (h0 + N) * cos_lambda * cos_phi;
			let y0 = (h0 + N) * cos_lambda * sin_phi;
			let z0 = (h0 + (1 - this.e_sq) * N) * sin_lambda;

			let t = cos_lambda * zUp - sin_lambda * yNorth;

			let zd = sin_lambda * zUp + cos_lambda * yNorth;
			let xd = cos_phi * t - sin_phi * xEast;
			let yd = sin_phi * t + cos_phi * xEast;

			return this.ConvertXYZToLLA({
					x: xd + x0,
					y: yd + y0,
					z: zd + z0
			})
	}
	_.prototype.radians = function (degree) {
			return this.PI / 180 * degree;
	}	 
	Cesium.ECEF = _;
}())

